package com.example.tccdemo.service;

import com.example.tccdemo.db163.dao.UserMapper;
import com.example.tccdemo.db163.model.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private CuratorFramework zkClient;

    public List<User> getAllUsers() {

        return userMapper.selectAllUsers();
    }

    public int delUser(Integer userId) {
        User user = userMapper.selectByPrimaryKey(userId);
        if (user != null) {
            log.info("用户存在，用户为：" + userId);
            return userMapper.deleteByPrimaryKey(userId);
        }
        log.info("用户不存在存在，用户为：" + userId);
        return 0;
    }

    public User selectById(Integer userId) {
        return userMapper.selectByPrimaryKey(userId);
    }

    public int updateUser(User user) {
        return userMapper.updateByPrimaryKeySelective(user);
    }


    /**
     * 有业务单号的insert操作,比如用户Id+商品Id,特惠,我们对insert也要进行幂等性,
     * 常见的场景,秒杀或者特惠,绑定同一个用户Id特价商品只能买一次,而不能多次购买,那么可以做幂等性
     * <p>
     * 没有业务单号的insert比如注册账号,点击多次的话,可以用token解决,进入注册页,后台系统统一生成一个token,返回前端隐藏域提交的时候一并提交
     * 根据这个token进行获取分布式锁,key就是token,完成insert操作,没有获取分布式锁的话,请求失败
     *
     * @param user
     * @param token
     * @return
     * @throws Exception
     */
    //TIPS 这里我遇到了一个坑点,就是zookeeper不知道里面什么组件会占用8080,然后就会导致一方起不来,这样的话用分布式锁做接口幂等性就不好做了
    //只有特殊的业务需求比如支付和下单页面才需要做幂等性接口验证,区分有业务单号和没有业务单号的方式,有业务单号就用这个业务单号获取分布式锁,没有的话用token
    public int insertUser(User user, String token) throws Exception {
        //如果提交数据没有业务唯一的字段,那么这个幂等性验证就由token来做
        InterProcessMutex lock = new InterProcessMutex(zkClient, "/" + token);
        //30秒过期分布式锁
        boolean isLock = lock.acquire(30, TimeUnit.SECONDS);
        if (isLock) {
            return userMapper.insertSelective(user);

        }
        return 0;
    }
}
